package com.xbongbong.paas.consumer;

import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.binders.BusinessRuleConsumerBinder;
import com.xbongbong.paas.constant.TimeConstant;
import com.xbongbong.paas.enums.BusinessRuleExecuteEnum;
import com.xbongbong.paas.enums.RuleOperationEnum;
import com.xbongbong.paas.redis.PaasRedisHelper;
import com.xbongbong.paas.redis.RedisPrefixConstant;
import com.xbongbong.paas.business.rule.BusinessRuleLogService;
import com.xbongbong.paas.service.BusinessRuleService;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.thread.TransmittableThreadLocalUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.pro.businessrule.pojo.dto.OperationDTO;
import com.xbongbong.pro.businessrule.pojo.dto.OperatorBatchDTO;
import com.xbongbong.pro.businessrulelog.pojo.BusinessRuleLogSaveDTO;
import com.xbongbong.pro.enums.ErrorCodeEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.errorcodes.BusinessRuleErrorCodeEnum;
import com.xbongbong.pro.form.pojo.RuleTargetPojo;
import com.xbongbong.pro.rabbitmq.constant.BusinessBinderConstant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;

/**
 * 业务规则消费者
 * @author 吴峰
 * @version v1.0
 * @date 2019/5/7 16:22
 * @since v1.0
 */
@EnableBinding(BusinessRuleConsumerBinder.class)
public class BusinessRuleCustomerListener {

    private static final Logger LOGGER = LoggerFactory.getLogger(BusinessRuleCustomerListener.class);



    private static final String CLOSE_BUSINESS_RULE_FLAG = "0";

    @Resource
    private PaasRedisHelper paasRedisHelper;
    @Resource
    private BusinessRuleService businessRuleService;
    @Resource
    private BusinessRuleLogService businessRuleLogService;



    @StreamListener(value = BusinessBinderConstant.RULE_INPUT)
    public void add(OperatorBatchDTO operationBatchDTO) throws Exception {
        LOGGER.info("business rule Received: "  + operationBatchDTO.getCorpid());
        consumer(operationBatchDTO);
    }



    @StreamListener(value = BusinessBinderConstant.IMPORT_RULE_INPUT)
    public void importRuleInput(OperatorBatchDTO operationBatchDTO) throws Exception {
        LOGGER.info("import business rule Received: "  + operationBatchDTO.getCorpid());
        consumer(operationBatchDTO);
    }


    private void consumer(OperatorBatchDTO operationBatchDTO) {
        String key;
        String prefix = RedisPrefixConstant.BUSINESS_RULE;
        String corpid = operationBatchDTO.getCorpid();
        String userId = operationBatchDTO.getUserId();
        StringBuilder stringBuilder = new StringBuilder();
        if (Objects.equals(SaasMarkEnum.SAAS.getCode(), operationBatchDTO.getSaasMark())) {
            // saas 的key
            key = stringBuilder.append(corpid).append("-").append(userId)
                    .append("-")
                    .append(operationBatchDTO.getBusinessType())
                    .append("-")
                    .append(operationBatchDTO.getFormId())
                    .append("-")
                    .append(operationBatchDTO.getDataId()).toString();
        } else {
            key = stringBuilder.append(corpid).append("-").append(userId)
                    .append("-")
                    .append(operationBatchDTO.getFormId())
                    .append("-")
                    .append(operationBatchDTO.getDataId()).toString();
        }
        try {
            LOGGER.info("business rule Received: "  + key);
            List<OperationDTO> operationList = operationBatchDTO.getOperationDtoList();
            for (OperationDTO operationDTO: operationList) {
                RuleTargetPojo ruleTargetPojo = operationDTO.getTarget();

                try {
                    long startTime = DateTimeUtil.getLong();
                    String flag = paasRedisHelper.getValue(prefix, key);
                    if (Objects.equals(CLOSE_BUSINESS_RULE_FLAG, flag)) {
                        // 由于前一条业务规则执行失败，该用户的这个业务表单的这条数据，不在执行下面的业务规则
                        if (Objects.isNull(operationBatchDTO.getLogId())) {
                            String messageMsg = String.format(I18nMessageUtil.getMessage(BusinessRuleErrorCodeEnum.API_ERROR_261013.getMsg()));
                            LOGGER.error("consumer consume fail：" + messageMsg);
                            BusinessRuleLogSaveDTO businessRuleLogSaveDTO = new BusinessRuleLogSaveDTO(operationBatchDTO.getSaasMark(), operationBatchDTO.getBusinessType(), operationBatchDTO.getFormId(), operationBatchDTO.getDataId(),
                                    corpid, operationBatchDTO.getLoginUser(), operationBatchDTO.getPlatform(), operationBatchDTO.getHttpHeader(), operationBatchDTO.getBrowserInfo(), operationBatchDTO.getIp(), operationBatchDTO.getLocale());
                            businessRuleLogSaveDTO.setBusinessRuleInfoId(operationDTO.getBusinessRuleInfoId());
                            businessRuleLogSaveDTO.setBusinessRuleType(operationDTO.getBusinessRuleType());
                            businessRuleLogSaveDTO.setOperationType(operationDTO.getOperationType());
                            businessRuleLogSaveDTO.setMessage(messageMsg);
                            businessRuleLogSaveDTO.setReason(BusinessRuleExecuteEnum.PASSIVE_ERROR.getCode());
                            businessRuleLogSaveDTO.setRedisKey(key);
                            businessRuleLogSaveDTO.setTarget(operationDTO.getTarget());
                            businessRuleLogService.log(businessRuleLogSaveDTO, 0, 0, 0);
                        }
                        continue;
                    }
                    // 子表单key
                    operationDTO.setCorpid(corpid);
                    operationDTO.setUserId(userId);
                    operationDTO.setLoginUser(operationBatchDTO.getLoginUser());
                    operationDTO.setPlatform(operationBatchDTO.getPlatform());
                    operationDTO.setHttpHeader(operationBatchDTO.getHttpHeader());
                    operationDTO.setBrowserInfo(operationBatchDTO.getBrowserInfo());
                    operationDTO.setIp(operationBatchDTO.getBrowserInfo());
                    operationDTO.setLocale(operationBatchDTO.getLocale());
                    Integer operationType = operationDTO.getOperationType();
                    RuleOperationEnum operationEnum = RuleOperationEnum.getByCode(operationType);
                    if (Objects.isNull(operationEnum)) {
                        continue;
                    }
                    LOGGER.info("business rule Received operator: " + key + ">>>" + operationEnum.getTip());

                    // 权限控制
                    TransmittableThreadLocalUtil.setValue(ruleTargetPojo.getLinkSaasMark(), ruleTargetPojo.getLinkBusinessType(), ruleTargetPojo.getMenuId(), operationBatchDTO.getDistributorMark());
                    switch (operationEnum) {
                        case ONLY_INSERT:
                            businessRuleService.onlyAdd(operationDTO);
                            break;
                        case UPDATE_AND_INSERT:
                            businessRuleService.addAndUpdate(operationDTO);
                            break;
                        case ONLY_UPDATE:
                            businessRuleService.onlyUpdate(operationDTO, null);
                            break;
                        case ONLY_DELETE:
                            businessRuleService.onlyDelete(operationDTO);
                            break;
                        default:
                            break;
                    }
                    LOGGER.info("Received: "  + operationEnum.getMemo());
                    long endTime = DateTimeUtil.getLong();
                    long time = endTime - startTime;
                    LOGGER.info("businessRule customer time :" + time);

                    if (Objects.nonNull(operationBatchDTO.getLogId())) {
                        // 将未消费的业务规则更新成消费成功
                        businessRuleLogService.update(operationBatchDTO.getLogId(), corpid, 1);
                    }
                } catch (XbbException e) {
                    LOGGER.error("BusinessRuleCustomerListener业务规则执行失败：" , e);
                    paasRedisHelper.setValue(prefix, key, CLOSE_BUSINESS_RULE_FLAG, TimeConstant.SECONDS_PER_DAY);
                    if (Objects.isNull(operationBatchDTO.getLogId())) {
                        BusinessRuleLogSaveDTO businessRuleLogSaveDTO = new BusinessRuleLogSaveDTO(operationBatchDTO.getSaasMark(), operationBatchDTO.getBusinessType(), operationBatchDTO.getFormId(), operationBatchDTO.getDataId(),
                                corpid, operationBatchDTO.getLoginUser(), operationBatchDTO.getPlatform(), operationBatchDTO.getHttpHeader(), operationBatchDTO.getBrowserInfo(), operationBatchDTO.getIp(), operationBatchDTO.getLocale());
                        businessRuleLogSaveDTO.setOperationType(operationDTO.getOperationType());
                        String message = String.format(I18nMessageUtil.getMessage(BusinessRuleErrorCodeEnum.API_ERROR_261014.getMsg()), e.getMsg());
                        businessRuleLogSaveDTO.setMessage(message);
                        businessRuleLogSaveDTO.setReason(BusinessRuleExecuteEnum.SELF_ERROR.getCode());
                        businessRuleLogSaveDTO.setRedisKey(key);
                        businessRuleLogSaveDTO.setBusinessRuleInfoId(operationDTO.getBusinessRuleInfoId());
                        businessRuleLogSaveDTO.setBusinessRuleType(operationDTO.getBusinessRuleType());
                        businessRuleLogSaveDTO.setTarget(operationDTO.getTarget());
                        businessRuleLogService.log(businessRuleLogSaveDTO, 0, 0, 0);
                    }
                }catch (Exception e) {
                    LOGGER.error("BusinessRuleCustomerListener业务规则执行失败，报错信息：" , e);
                    paasRedisHelper.setValue(prefix, key, CLOSE_BUSINESS_RULE_FLAG, TimeConstant.SECONDS_PER_DAY);
                    if (Objects.isNull(operationBatchDTO.getLogId())) {
                        BusinessRuleLogSaveDTO businessRuleLogSaveDTO = new BusinessRuleLogSaveDTO(operationBatchDTO.getSaasMark(), operationBatchDTO.getBusinessType(), operationBatchDTO.getFormId(), operationBatchDTO.getDataId(),
                                corpid, operationBatchDTO.getLoginUser(), operationBatchDTO.getPlatform(), operationBatchDTO.getHttpHeader(), operationBatchDTO.getBrowserInfo(), operationBatchDTO.getIp(), operationBatchDTO.getLocale());
                        businessRuleLogSaveDTO.setOperationType(operationDTO.getOperationType());
                        String message = String.format(I18nMessageUtil.getMessage(BusinessRuleErrorCodeEnum.API_ERROR_261014.getMsg()), e.getMessage());
                        businessRuleLogSaveDTO.setMessage(message);
                        businessRuleLogSaveDTO.setReason(BusinessRuleExecuteEnum.SELF_ERROR.getCode());
                        businessRuleLogSaveDTO.setRedisKey(key);
                        businessRuleLogSaveDTO.setBusinessRuleInfoId(operationDTO.getBusinessRuleInfoId());
                        businessRuleLogSaveDTO.setBusinessRuleType(operationDTO.getBusinessRuleType());
                        businessRuleLogSaveDTO.setTarget(operationDTO.getTarget());
                        businessRuleLogService.log(businessRuleLogSaveDTO, 0, 0, 0);
                    }
                }
            }
            // 清掉由于上面报错设置的redis
            paasRedisHelper.removeValue(prefix, key);
        } catch (Exception e) {
            LOGGER.error("consumer consume fail 业务异常：" , e);
        }
    }

}
